﻿using DapperLambdaSQL.Utils;

namespace DapperLambdaSQL.Model
{
    /// <summary>
    /// SQL WHERE 子句 运算符
    /// </summary>
    public class SQLOperator
    {
        private BooleanConvertType booleanConvertType;

        private string sqlWhere;

        /// <summary>
        /// 是否已经传值
        /// </summary>
        public bool IsParame { get; private set; }

        private SQLOperator(string sqlWhere, bool isParame = false)
        {
            this.sqlWhere = sqlWhere;
            IsParame = isParame;
        }

        public void SetBooleanConvertType(BooleanConvertType booleanConvertType)
        {
            this.booleanConvertType = booleanConvertType;
        }

        /// <summary>
        /// 条件语句
        /// </summary>
        public string SqlWhere
        {
            get
            {
                sqlWhere = booleanConvertType == BooleanConvertType.Bit_10
                    ? sqlWhere.Replace("#true#", "1").Replace("#false#", "0")
                    : sqlWhere.Replace("#true#", "'Y'").Replace("#false#", "'N'");
                return sqlWhere;
            }
        }

        private static string WhereSql<T>(string @operator, T value)
        {
            var isValueType = ReflectionUtility.IsValueType<T>();
            if (!isValueType) return "{0}" + $" {@operator} '{value}' ";

            if (value is bool b)
            {
                return "{0}" + $" {@operator} {(b ? "#true#" : "false")} ";
            }

            return "{0}" + $" {@operator} {value}";
        }

        private static string WhereSql(string @operator)
        {
            return "{0} " + @operator + " @{0}";
        }

        private static SQLOperator Crate<T>(string @operator, T value)
        {
            return new SQLOperator(WhereSql(@operator, value), true);
        }

        private static SQLOperator Crate(string @operator)
        {
            return new SQLOperator(WhereSql(@operator), false);
        }

        /// <summary>
        /// 等于[=]
        /// </summary>
        public static SQLOperator equal => Crate(SqlKeyWord.Equal);

        /// <summary>
        /// 等于[=]
        /// </summary>
        public static SQLOperator Equal<T>(T value) => Crate(SqlKeyWord.Equal, value);

        /// <summary> 不等于[<>] 谨慎使用 不等于 操作符，引擎将放弃使用索引而进行全表扫描 </summary>
        public static SQLOperator unqual => Crate(SqlKeyWord.Unqual);

        /// <summary> 不等于[<>] 谨慎使用 不等于 操作符，引擎将放弃使用索引而进行全表扫描 </summary>
        public static SQLOperator Unqual<T>(T value) => Crate(SqlKeyWord.Unqual, value);

        /// <summary>
        /// 大于[&gt;]
        /// </summary>
        public static SQLOperator great => Crate(SqlKeyWord.Great);

        /// <summary>
        /// 大于[&gt;]
        /// </summary>
        public static SQLOperator Great<T>(T value) => Crate(SqlKeyWord.Great, value);

        /// <summary>
        /// 大于等于[&gt;=]
        /// </summary>
        public static SQLOperator greatOrEqual => Crate(SqlKeyWord.GreatOrEqual);

        /// <summary>
        /// 大于等于[&gt;=]
        /// </summary>
        public static SQLOperator GreatOrEqual<T>(T value) => Crate(SqlKeyWord.GreatOrEqual, value);

        /// <summary> 小于[<] </summary>
        public static SQLOperator less => Crate(SqlKeyWord.Less);

        /// <summary> 小于[<] </summary>
        public static SQLOperator Less<T>(T value) => Crate(SqlKeyWord.Less, value);

        /// <summary> 小于等于[<=] </summary>
        public static SQLOperator lessOrEqual => Crate(SqlKeyWord.LessOrEqual);

        /// <summary> 小于等于[<=] </summary>
        public static SQLOperator LessOrEqual<T>(T value) => Crate(SqlKeyWord.LessOrEqual, value);

        /// <summary>
        /// 全匹配 %LIKE% 谨慎使用 LIKE,将会导致引擎放弃使用索引而进行全表扫描
        /// </summary>
        public static SQLOperator like => new SQLOperator("{0} LIKE '%{1}%' ");

        public static SQLOperator Like<T>(T value)
        {
            return new SQLOperator("{0} LIKE " + $"'%{value}%' ");
        }

        /// <summary>
        /// 右匹配 LIKE%
        /// </summary>
        public static SQLOperator rightLike => new SQLOperator("{0} LIKE '{1}%' ");

        /// <summary>
        /// 右匹配 LIKE%
        /// </summary>
        public static SQLOperator RightLike<T>(T value)
        {
            return new SQLOperator("{0} LIKE " + $"'{value}%' ");
        }

        /// <summary>
        /// 左匹配 %LIKE 谨慎使用 LIKE,将会导致引擎放弃使用索引而进行全表扫描
        /// </summary>
        public static SQLOperator leftLike => new SQLOperator("{0} LIKE '%{1}' ");

        /// <summary>
        /// 左匹配 %LIKE 谨慎使用 LIKE,将会导致引擎放弃使用索引而进行全表扫描
        /// </summary>
        public static SQLOperator LeftLike<T>(T value)
        {
            return new SQLOperator("{0} LIKE " + $"'%{value}' ");
        }

        /// <summary>
        /// BETWEEN 操作
        /// </summary>
        public static SQLOperator Between<T>(T value1, T value2)
        {
            return new SQLOperator("{0} BETWEEN '{1}' AND '{2}' ");
        }

        /// <summary>
        /// In 操作 谨慎使用 IN,将会导致引擎放弃使用索引而进行全表扫描 对于连续的数值,可选用 BETWEEN
        /// </summary>
        public static SQLOperator In => new SQLOperator("{0} IN {1} ");

        /// <summary>
        /// NotIn 操作 谨慎使用 NOTIN,将会导致引擎放弃使用索引而进行全表扫描
        /// </summary>
        public static SQLOperator NotIn => new SQLOperator("{0} NOT IN {1} ");
    }
}